#include "buycatalog.h"
#include "productinfo.h"
#include "mainwindow.h"

#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include <QtCore/QMetaType>
#include <QtGui/QMessageBox>
#include <QtCore/QDirIterator>
#include <QProgressDialog>

Q_DECLARE_METATYPE(IAPClient::ProductDataList)  //to be able to transfer data this type with Qt::QueuedConnection

#define INVALID_VALUE -1
/*
 * BuyCatalog - a QDialog inherited class wich will display a list of available
 * products allowing the user to trigger the In-Application Purchase experience
 * at a click of a button.
 *
 * This constuctor reads a list of product IDs from the catalog.dat file and
 * asks for the corresponding product data (IAPClient::ProductData) which the
 * API will fetch from Ovi.
 */
BuyCatalog::BuyCatalog(QWidget *parent)
    : QDialog(parent),
      productsRequested(0),
      current_requestId(INVALID_VALUE),
      infoDialog(NULL)
{
    // required so that IAPClient::ProductData can be queued in the signal
    qRegisterMetaType<IAPClient::ProductDataHash>("IAPClient::ProductDataHash");

    qDebug() << "::. Catalog constuctor";
    iap_client = new IAPClient(this);
    ui.setupUi(this);
    ui.listWidget->setStyleSheet(QString::fromUtf8("QListWidget{ background-color: grey; border-style: outset; border-width: 1px; border-radius: 1px; border-color: black;  selection-color: black; selection-background-color: red; }" \
                                                   "QPushButton{ background-color: green; border-style: outset; border-width: 2px; border-radius: 10px; border-color: beige; font: bold 14px; min-width: 4em; max-width:5em; padding: 6px; }" \
                                                   "QPushButton:pressed { background-color: rgb(224, 0, 0); border-style: inset;}"));

    connect(ui.listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(moreProductInfo(QListWidgetItem*)));
    Q_ASSERT(parent);
    connect(ui.backButton, SIGNAL(clicked()), parent, SLOT(catalogClosed()));
    connect(ui.restoreButton, SIGNAL(clicked()), this, SLOT(restoreProducts()));

    ui.backButton->setEnabled(false);
    ui.restoreButton->setEnabled(false);

    QString filepath = QApplication::applicationDirPath();
    filepath.append("/drm/data");

    QFile file(filepath);
    file.open(QFile::ReadOnly);

    QDirIterator dirit(filepath, QDir::Dirs, QDirIterator::NoIteratorFlags);
    while(dirit.hasNext())
    {
        QString dir = dirit.next();
        if(dir.contains("resourceid_", Qt::CaseInsensitive))
        {
            // breakdown the !:/private/<SID>/drm/data/resourceid_<productID>/
            // extract the product to which this file belongs
            QString product;
            QStringList elem = dir.split("_", QString::SkipEmptyParts);
            elem=elem[1].split("/", QString::SkipEmptyParts);
            product = elem[0].trimmed();
            if(!product.isEmpty())
            {
                if(!isProductActivated(product))
                {
                    products.append(product);
                    qDebug() << "++ ProductID " << product << " to be puchased.";
                }
                else
                {
                    qDebug() << "++ ProductID " << product << " is activated.";
                }
            }
        }
    }

    //qDebug() << "Products list count: " << products.count();

    if(products.count()>0)
    {
        // connect IAP API's signals to app's slots
        connect(iap_client, SIGNAL(productDataReceived( int, QString, IAPClient::ProductDataHash)), this,
                SLOT(productDataReceived(int, QString, IAPClient::ProductDataHash)), Qt::QueuedConnection);
        connect(iap_client, SIGNAL(purchaseCompleted( int , QString, QString)), this,
                SLOT(purchaseCompleted( int , QString, QString)),Qt::QueuedConnection);
        connect(iap_client, SIGNAL(purchaseFlowFinished(int)), this, SLOT(purchaseFlowFinished(int)), Qt::QueuedConnection);

        ui.progressBar->setRange(0, products.count());
        ui.progressBar->setTextVisible(false);

        // request product data from Ovi for the products
        requestNextProduct();
    }
    else
        ui.progressBar->setVisible(false);

    ui.backButton->setEnabled(true);

    connect(iap_client, SIGNAL(restorableProductsReceived( int, QString, IAPClient::ProductDataList)), this,
            SLOT(restorableProductsReceived( int, QString, IAPClient::ProductDataList)));
    connect(iap_client, SIGNAL(restorationCompleted(int, QString, QString)), this,
            SLOT(restorationCompleted(int, QString, QString)),Qt::QueuedConnection);

    busyIndicator = new QProgressDialog("", "", 1, 1, this);
    busyIndicator->setCancelButton(NULL);
    busyIndicator->setWindowModality(Qt::WindowModal);

    qDebug() << ".:: Catalog constuctor";
}

/*
 *
 *
 *
 */
BuyCatalog::~BuyCatalog()
{
    delete infoDialog;
    delete iap_client;
}

/*
 *
 *
 *
 */
void BuyCatalog::infoDialogClosed(int result)
{
    if(result==QDialog::Accepted)
    {
        IAPClient::ProductDataHash info = available_products[current_product_index];
        current_requestId = iap_client->purchaseProduct(info.value("id").toString(), IAPClient::ForcedAutomaticRestoration);
    }
}

/*
 *
 *
 *
 */
void BuyCatalog::moreProductInfo(QListWidgetItem* item)
{
    qDebug() << "::. moreProductInfo";

    if(infoDialog!=NULL)
    {
        disconnect(infoDialog, SIGNAL(finished(int)), this, SLOT(infoDialogClosed(int)));
        delete infoDialog;
        infoDialog = NULL;
    }

    current_product_index = ui.listWidget->row(item);
    IAPClient::ProductDataHash info = available_products[current_product_index];
    // create a dialog for showing detailed product info
    infoDialog = new ProductInfo(info.value("info").toString(), info.value("description").toString(), info.value("price").toString(), this);
    // get notified when the product info dialog is closed
    connect(infoDialog, SIGNAL(finished(int)), this, SLOT(infoDialogClosed(int)));
    // show the dialog
    infoDialog->showFullScreen();

    qDebug() << ".:: moreProductInfo";
}

/*
 * Returns true if the product files can be accessed or false if the purchase/restore is needed
 */
bool BuyCatalog::isProductActivated(QString product)
{
    // ToDo: construct path, find first file and attempt to open it
    // return false if open request fails with DRM access code
    return false;
}

/*
 *
 *
 *
 */
void BuyCatalog::buyProduct()
{
    qDebug() << "::. buyProduct";

    // locate the list item which holds the button that send a signal to this slot
    QWidget *clickedWidget = qobject_cast<QWidget *>(sender()->parent());
    for (int index = 0; index < ui.listWidget->count(); index++)
    {
        QListWidgetItem *runningItem = ui.listWidget->item(index);
        QWidget *widget = ui.listWidget->itemWidget(runningItem);
        if (clickedWidget == widget)
                {
                IAPClient::ProductDataHash info = available_products[index];
                // issue a buy request for the corresponding product
                // if the user has paid for this content already, restoration of the license is needed
                current_productId = info.value("id").toString();
                current_requestId = iap_client->purchaseProduct(current_productId, IAPClient::ForcedAutomaticRestoration);
                break;
                }
    }

    qDebug() << ".:: buyProduct";
}

/*
 *
 *
 *
 */
void BuyCatalog::productDataReceived( int requestId, QString status, IAPClient::ProductDataHash productData )
{
    qDebug() << "::. productDataReceived";

    //Q_ASSERT(requestId == current_requestId);
	
    if(QString::compare(status, "OK", Qt::CaseInsensitive)==0)
    {
        available_products.append(productData);

        // add a new item to the products catalog UI's list
        QListWidgetItem *item = new QListWidgetItem();
        ui.listWidget->addItem(item);
        QLabel *labelTitle = new QLabel(productData.value("info").toString());
        QLabel *labelPrice = new QLabel(productData.value("price").toString());
        QHBoxLayout *layoutTitleAndPrice= new QHBoxLayout();
        layoutTitleAndPrice->addWidget(labelTitle);
        layoutTitleAndPrice->addWidget(labelPrice);
        QPushButton *button = new QPushButton(tr("Buy..."));
        QLabel *labelShort = new QLabel(productData.value("shortdescription").toString());
        QHBoxLayout *layoutShortBuy= new QHBoxLayout();
        layoutShortBuy->addWidget(labelShort);
        layoutShortBuy->addWidget(button);
        QVBoxLayout *layoutItem = new QVBoxLayout();
        layoutItem->addItem(layoutTitleAndPrice);
        layoutItem->addItem(layoutShortBuy);
        QWidget *widget = new QWidget();
        widget->setLayout(layoutItem);
        item->setSizeHint(widget->sizeHint());
        ui.listWidget->setItemWidget(item, widget);

        // if multiple products are available, let's highlight the one that triggered the shopping session
        if( productData.value("id").toString() == defaultProduct)
            ui.listWidget->setCurrentItem(item);

        connect(button, SIGNAL(clicked()), this, SLOT(buyProduct()));
    }
    else // what are all the possible status messages?
    {
        // the product is not available for one reason or another?
        // probably you can ignore this
        // or report it to your server for analysis
        qDebug() << "Requested product could not be retrived: " << status;
    }

    // if we don't have any more products ...
    if(productsRequested == products.count())
    {
        ui.progressBar->setVisible(false);

        // have we got any product data?
        if(!available_products.count())
        {
                QMessageBox message;
                message.setText(tr("No products available. Please try again later!"));
                message.exec();

                // close catalog
                reject();
        }
    }
    else
    {
        // let's look for the next product's data
        requestNextProduct();
    }

    qDebug() << ".:: productDataReceived";
}

/*
 *
 *
 *
 */
void BuyCatalog::requestNextProduct()
{
    qDebug() << "::. requestNextProduct";

    if(productsRequested < products.count())
    {
        QString prod = products[productsRequested++];
        current_requestId = iap_client->getProductData(prod);
        qDebug() << "+ Request for product" << prod << " returned id: " << current_requestId;
        ui.progressBar->setValue(productsRequested-1);
    }
    else
        ui.progressBar->setValue(productsRequested);

    if(productsRequested == products.count() - 1){
        ui.restoreButton->setEnabled(true);
    }

    qDebug() << ".:: requestNextProduct";
}

/*
 *
 *
 *
 */
void BuyCatalog::purchaseCompleted( int requestId, QString status, QString purchaseTicket )
{
    qDebug() << "::. purchaseCompleted with status: " << status;

    if(requestId != current_requestId)
        return;

    if(QString::compare(status, "OK", Qt::CaseInsensitive)==0
         || QString::compare(status, "RestorableProduct", Qt::CaseInsensitive)==0)
    {
        MainWindow::saveTicket(purchaseTicket, current_productId);
        // In-Application Purchase API will take care of downloading the DRM license
        // the files covered by this license will become accessible
    }
    else
    {
        // some error
        // error message already displayed by In-Application Purchase UI, may also be reflected in app's UI.
    }

    qDebug() << ".:: purchaseCompleted";
}

/*
 *
 *
 *
 */
void BuyCatalog::userAndDeviceDataReceived( int /*requestId*/, QString /*status*/,
                                            IAPClient::UserAndDeviceDataHash /*userdata*/ )
{
    qDebug() << "::. userAndDeviceDataReceived";

    qDebug() << ".:: userAndDeviceDataReceived";
}

/*
 *
 *
 *
 */
void BuyCatalog::restorableProductsReceived( int requestId, QString status,
                                             IAPClient::ProductDataList items )
{
    qDebug() << "::. restorableProductsReceived with status: " << status;
    if(requestId != current_requestId){
        qDebug() << "::. restorableProductsReceived failed ";
        return;
    }

    current_requestId = INVALID_VALUE;

    if(!items.empty()){
        restorableProductItems.append(items);
        current_productId = restorableProductItems.takeFirst().value("id").toString();
        current_requestId = iap_client->restoreProduct(current_productId);
    }

    if(current_requestId == INVALID_VALUE){
        busyIndicator->close();
        ui.backButton->click();
    }else{
        ui.progressBar->setRange(0, restorableProductItems.count() + 1);
        ui.progressBar->setTextVisible(false);
        ui.progressBar->setVisible(true);
    }
}

/*
 *
 *
 *
 */
void BuyCatalog::restorationFlowFinished( int requestId )
{
    qDebug() << "::. restorationFlowFinished";

    qDebug() << ".:: restorationFlowFinished";
}

/*
 *
 *
 *
 */
void BuyCatalog::restorationCompleted( int requestId, QString status, QString purchaseTicket )
{
    qDebug() << "::. restorationCompleted with status: " << status;

    purchaseCompleted(requestId, status, purchaseTicket);

    if(restorableProductItems.empty()){
        busyIndicator->close();
        ui.backButton->click();
    }else{
        ui.progressBar->setValue(ui.progressBar->value() + 1);
        current_productId = restorableProductItems.takeFirst().value("id").toString();
        current_requestId = iap_client->restoreProduct(current_productId);
    }

    qDebug() << ".:: restorationCompleted";
}

/*
 *
 *
 *
 */
void BuyCatalog::purchaseFlowFinished( int requestId )
{
    qDebug() << "::. purchaseFlowFinished";

    // now the user is back in app's UI

    qDebug() << ".:: purchaseFlowFinished";
}


void BuyCatalog::restoreProducts()
{
    current_requestId = iap_client->getRestorableProducts();
    if(current_requestId < 0)
        return;

    //lock ui
    busyIndicator->setLabelText("restoration in progress...");
    busyIndicator->show();

    restorableProductItems.clear();
}

// End of the file.

